import React, {
	PropsWithChildren,
	ReactNode,
	useMemo,
  useState,
  useRef,
  useEffect,
  CSSProperties
} from "react";
import styled from "styled-components";
import { color, typography } from "../shared/style";
import { darken, rgba, opacify } from "polished";
import { easing } from "../shared/animation";

import { Icon } from '../icon/index'

export function throttle(fn: Function, delay: number = 300) {
	let flag = true;
	return function(...args: any) {
		if (flag) {
			flag = false;
			fn(...args);
			setTimeout(() => {
				flag = true;
			}, delay);
		}
	};
}

const source = [
	{
		value: "北京分行",
		children: [
			{
				value: "朝阳支行办事处",
				children: [
					{ value: "朝阳支行办事处-1" },
					{ value: "朝阳支行办事处-2" },
				],
			},
			{ value: "海淀支行办事处" },
			{ value: "石景山支行办事处" },
		],
	},
	{
		value: "天津分行",
		children: [
			{ value: "和平支行办事处" },
			{ value: "河东支行办事处" },
			{ value: "南开支行办事处" },
		],
	},
];

const flatten = function(
  list: Array<itemProps>,
  level = 1,
  parent: itemProps,
  defaultExpand = true
): itemPropsRequired[] {
  let arr: itemPropsRequired[] = []; //收集所有子项
  list.forEach((item) => {
    item.level = level;
    if(item.expand === undefined){
      item.expand = defaultExpand;
    }
    if(item.visible === undefined){
      item.visible = true;
    }
    if(!parent.expand || !parent.visible){
      item.visible = false;
    }
    if(item.key === undefined){
      item.key = item.value + Math.random();
    }
    item.parent = parent;
    arr.push(item as itemPropsRequired);
    if(item.children){
      arr.push(
        ...flatten(
          item.children,
          level + 1,
          item,
          defaultExpand
        )
      )
    }
  })
  return arr;
}

const img = new Image();
img.src = "https://www.easyicon.net/api/resizeApi.php?id=1200841&size=32";

interface itemProps{
  value: string;
  children?: Array<itemProps>,
  level?: number,
  expand?: boolean,
  visible?: boolean,
  key?: string,
  parent?: itemProps,
}

interface itemPropsRequired extends Omit<Required<itemProps>, "children" | "parent">{
  children?: itemPropsRequired[];
  parent: itemPropsRequired;
}

const checkParent = function(g: itemPropsRequired){
  return g.level === 1;
};

const levelSpace = 20; //同级生效间距

const originPadding = 24; //原始间距

// 1插上级 2插同级 3插下级 0不插
const switchInsert = function(diff: number, g: itemPropsRequired){
  if(!isNaN(diff)){
    const origin = g.level * originPadding; //目标原本padding
    if(diff < origin){
      // 移动到padding前全部算上级
      if(checkParent(g)){
        return 2;
      }else{
        return 1;
      }
    }else if(diff < origin + levelSpace){
      return 2;
    }else{
      return 3;
    }
  }else{
    return 0
  }
}

const findOrigin = function(key: string, data: itemPropsRequired[]){
  const res = data.filter((v) => v.key === key);
  if(res.length > 0){
    return res[0];
  }else{
    return null;
  }
}

const getParent = function(g: itemPropsRequired){
  if(g.parent && g.parent.parent){
    return g.parent.parent;
  }else{
    return g.parent;
  }
}

const checkTargetOrigin = function(g: itemPropsRequired, origin: itemPropsRequired){
  return g !== origin;
}

const judgeChildren = function(origin: itemPropsRequired, target: itemPropsRequired){
  let sign = true; //如果有孩子就是false
  const fn = (child: itemPropsRequired) => {
    if(child.children){
      child.children.forEach((v) => {
        if(v === target){
          sign = false;
          return;
        }
        fn(v);
      })
    }
  }
  fn(origin);
  return sign;
}

const changeOriginParent = function(origin: itemPropsRequired){
  const parent = origin.parent;
  if(parent.children){
    const index = parent.children.indexOf(origin);
    if(index > -1){
      parent.children.splice(index, 1);
    }
  }
}

const changeTargetParent = function(
  parent: itemPropsRequired,
  origin: itemPropsRequired,
  g: itemPropsRequired
){
  origin.parent = parent;
  if(parent.children){
    // 判断插入父级节点哪里
    if(g.parent.children){
      const index = g.parent.children.indexOf(g);
      if(index > -1){
        parent.children.splice(index + 1, 0, origin);
      }else{
        //parent传递g会进来
				parent.children.push(origin);
      }
    }else{
      parent.children.push(origin);
    }
  }else{
    parent.children = [origin];
  }
}

const insertTop = function(
  key: string,
  g: itemPropsRequired,
  data: itemPropsRequired[],
  callback: Function
){
  const origin = findOrigin(key, data); // 根据key找到拖拽数据
  // 拖拽数据插入target上级
  const parent = getParent(g); //获取目标数据的上级
  if(g.level !== 1 && origin && checkTargetOrigin(g, origin) && judgeChildren(origin, g)){
    // 修改拖拽数据父节点数据
    changeOriginParent(origin);
    // 修改目标父节点的父节点（与父节点同级）
    changeTargetParent(parent, origin, g);
    callback();
  }
}

const insertMiddle = function(
	key: string,
	g: itemPropsRequired,
	data: itemPropsRequired[],
	callback: Function
) {
	const origin = findOrigin(key, data);
	//origin插入target同级
	const parent = g.parent;
	if (
		g.level !== 0 &&
		origin &&
		checkTargetOrigin(g, origin) &&
		judgeChildren(origin, g)
	) {
		changeOriginParent(origin);
		changeTargetParent(parent, origin, g);
		callback();
	}
};

const insertLower = function(
	key: string,
	g: itemPropsRequired,
	data: itemPropsRequired[],
	callback: Function
) {
	const origin = findOrigin(key, data);
	const parent = g;
	if (origin && checkTargetOrigin(g, origin) && judgeChildren(origin, g)) {
		changeOriginParent(origin);
		changeTargetParent(parent, origin, g);
		callback();
	}
};

export type TreeProps = {
  /** 数据源*/
	source: itemProps[];
	/** 是否可以拖拽 */
	drag?: boolean;
	/** 高亮边框颜色 */
	borderColor?: string;
	/** 拖拽提示色 */
	backColor?: string;
	/**外层样式*/
	style?: CSSProperties;
	/**外层类名*/
	classname?: string;
}

const changeVisible = (item: itemPropsRequired, callback: Function) => {
  //给点击的children设置visible
	if (item.children) {
		//避免children有显示不一行为
		let visible: boolean;
		const depth = (item: itemPropsRequired[]) => {
			item.forEach((v) => {
				if (visible === undefined) {
					visible = !v.visible;
				}
				v.visible = visible;
				if (v.children) {
					//把孩子全部改掉
					depth(v.children);
				}
			});
		};
		depth(item.children);
		callback(); //改完后更新页面
	}
}

interface TreeItemType {
  level: number;
  itemkey: string;
  highlight: DragHighlight;
}

const TreeItem = styled.div<TreeItemType>`
	padding-left: ${(props) => originPadding * props.level}px;
	padding-top: 2px;
	padding-bottom: 2px;
	display: flex;
	align-items: center;
	position: relative;
  overflow: hidden;
  ${(props) => {
		if (props.highlight.drag && props.highlight.itemkey === props.itemkey) {
			return "border: 1px dashed #53c94fa8;";
		} else {
			return "";
		}
	}}
`;

const TreeIcon = styled.span<{ g: itemPropsRequired }>`
	& > svg {
		transition: linear 0.2s;
		height: 10px;
		margin-bottom: 5px;
		${(props) => {
			if (props.g.children && props.g.children.length !== 0) {
				if (props.g.children[0] && props.g.children[0]["visible"]) {
					return "display:inline-block;transform: rotate(-90deg);";
				} else {
					return "display:inline-block;";
				}
			} else {
				return "opacity:0";
			}
		}};
	}
`;

interface DragControlData{
  drag: boolean;
  x: number;
  itemkey: string;
}

interface DragHighlight{
  drag: boolean;
  itemkey: string;
}

type TreeGragType = { gkey: string } & DragControlData;

const TreeGrag = styled.div<TreeGragType>`
	position: absolute;
	width: 100%;
	height: 90%;
	${(props) => {
		switch (props.x) {
			case 1:
				return `margin-left:${-levelSpace}px ;`;
			case 2:
				return "";
			case 3:
				return `margin-left:${levelSpace}px  ;`;
			default:
				return "";
		}
	}};
	${(props) => {
		if (props.itemkey === props.gkey) {
			return "background: #00000030;";
		}
	}}
`;

export function Tree(props: TreeProps) {
  const root = useMemo(() => {
    return {
      value: 'root',
      children: source,
      level: 0,
      expand: true,
      visible: true
    }
  }, [source]);
  const [dragUpdate, setDragUpdate] = useState(0);
  const [dragOver, setDragOver] = useState<DragControlData>({
    drag: false,
    x: 0,
    itemkey: "",
  });
  const [highlight, setHighlight] = useState({
		drag: true,
		itemkey: "",
	});
  const data = useMemo(() => {
    return flatten(root.children, 1, root);
  }, [root, dragUpdate]);
  const [start, setStart] = useState(0);
  const forceUpdate = useState(0)[1];
  const ref = useRef<HTMLDivElement>(null);
  const dragHandler = (
    clientX: number,
    itemkey: string,
    g: itemPropsRequired
  ) => {
    const diff = clientX - start;
    const x = switchInsert(diff, g);
    setDragOver({
      drag: true,
      x, 
      itemkey
    })
  };
  useEffect(() => {
    if(ref.current){
      setStart(ref.current.getBoundingClientRect().left); //为了找到起始
    }
  }, []);
  useEffect(() => {
		const handler = () => {
			setDragOver((prev) => ({ ...prev, drag: false }));
		};

		window.addEventListener("dragend", handler);
		return () => {
			window.removeEventListener("dragend", handler);
		};
  }, []);
  useEffect(() => {
		const handler = () => {
			setDragOver((prev) => ({ ...prev, drag: false }));
			setHighlight({
				drag: false,
				itemkey: "",
			});
		};
		window.addEventListener("dragend", handler);
		return () => {
			window.removeEventListener("dragend", handler);
		};
	}, []);
  const callback = () => {
    forceUpdate((state) => state + 1);
  };
  const dragCallback = () => {
    setDragUpdate((state) => state + 1);
  };
	return (
    <div ref={ref}>
      {
        data.filter((v) => v.visible === true)
          .map((g) => (
            <TreeItem
              itemkey={g.key}
              highlight={highlight}
							level={g.level}
							draggable
							onClick={() => changeVisible(g, callback)}
							key={g.key}
							onDragStart={(e) => {
								e.dataTransfer.setData("atomkey", `${g.key}`);
                e.dataTransfer.setDragImage(img, 29, 29);
                setHighlight({
                  drag: true,
                  itemkey: g.key
                })
							}}
							onDragOver={(e) => {
                e.preventDefault();
                throttle(dragHandler)(e.clientX, g.key, g);
							}}
							onDrop={(e) => {
								const key = e.dataTransfer.getData("atomkey");
								const left = e.clientX;
								const diff = left - start; //离顶部差值
								const res = switchInsert(diff, g);
								switch (res) {
									case 1:
										insertTop(key, g, data, dragCallback);
										break;
									case 2:
										insertMiddle(
											key,
											g,
											data,
											dragCallback
										);
										break;
									case 3:
										insertLower(key, g, data, dragCallback);
										break;
									default:
										break;
								}
							}}
						>
              {dragOver.drag && (
								<TreeGrag
									gkey={g.key}
									drag={dragOver.drag}
									x={dragOver.x}
									itemkey={dragOver.itemkey}
								></TreeGrag>
							)}
							<TreeIcon g={g}>
								<Icon icon="arrowdown"></Icon>
							</TreeIcon>
							<span>{g.value}</span>
						</TreeItem>
          ))
      }
    </div>
  )
}

Tree.defaultProps = {
  source: [],
  drag: true,
  borderColor: "#53c94fa8",
	backColor: "#00000030",
}
